package com.aip;

/**
 * A cool byte cope class.
 * 一个很酷的字节处理类.
 * 
 * @contributor amin2312(aminlab@qq.com)
 * @createDate 2014-09-15
 */
public class ByteCool {
    /**
     * Length.
     * 长度.
     */
    private int _length;
    /**
     * Position.
     * 位置.
     */
    private int _position;
    /**
     * Size.
     * 大小.
     */
    private int _size;
    /**
     * Buffer.
     * 缓冲区.
     */
    public byte[] BUF;

    /**
     * Constructor.
     * 构造函数.
     */
    public ByteCool() {

    }

    /**
     * Constructor 2.
     * 构造函数(2).
     */
    public ByteCool(byte[] bytes) {
        this._length = 0;
        this._position = 0;
        this._size = bytes.length;
        this.BUF = bytes;
    }

    /**
     * Constructor 3.
     * 构造函数(3).
     */
    public ByteCool(int initSize) {
        this._length = 0;
        this._position = 0;
        this._size = initSize;
        this.BUF = new byte[this._size];
    }

//================================================
//
//  property
//	属性
//
//================================================

    /**
     * Get position.
     * 获取位置.
     */
    public int GetPosition() {
        return this._position;
    }

    /**
     * Set position.
     * 设置位置.
     */
    public void SetPosition(int value) {
        if (value > this._length) {
            value = this._length;
        }
        this._position = value;

    }

    /**
     * Move position.
     * 移动位置.
     */
    public void MovPosition(int value) {
        value += this._position;
        if (value > this._length) {
            value = this._length;
        }
        this._position = value;
    }

    /**
     * Get length.
     * 获取长度.
     */
    public int GetLength() {
        return this._length;
    }

    /**
     * Set length.
     * 设置长度.
     */
    public void SetLength(int value) {
        if (value > this._size) {
            value = this._size;
        }
        this._length = value;
    }

    /**
     * Move length.
     * 移动长度.
     */
    public void MovLength(int value) {
        value += this._length;
        if (value > this._size) {
            value = this._size;
        }
        this._length = value;
    }

    /**
     * Get size.
     * 获取大小.
     */
    public int GetSize() {
        return this._size;
    }

    /**
     * Set size.
     * 设置大小.
     */
    public void SetSize(int value) {
        if (value > this.BUF.length) {
            byte[] dest = new byte[value];
            this.copyBytes(this.BUF, 0, dest, 0, this._length);
            this.BUF = dest;
        }
        this._size = value;
    }

    /**
     * Get the number of bytes of the readable data.
     * 获取可读字节数.
     */
    public int GetBytesReadable() {
        return this._length - this._position;
    }

    /**
     * Get the number of bytes of the writeable data.
     * 获取可写字节数.
     */
    public int GetBytesWriteable() {
        return this._size - this._length;
    }

//================================================
//
//	read
//	读取
//
//================================================

    /**
     * Read a byte(8 bits).
     * 读取一个字节.
     */
    public byte ReadInt8() {
        byte value = this.BUF[this._position];
        this.MovPosition(1);
        return value;
    }

    /**
     * Read a unsigned byte(8 bits).
     * 读取一个无符号字节.
     */
    public byte ReadUint8() {
        byte value = this.BUF[this._position];
        this.MovPosition(1);
        return value;
    }

    /**
     * Read a short(16 bits).
     * 读取一个双字节.
     */
    public short ReadInt16() {
        short value = 0;
        value |= (this.BUF[this._position] & 0xFF);
        value |= ((this.BUF[this._position + 1] & 0xFF) << 8);
        this.MovPosition(2);
        return value;
    }

    /**
     * Read a unsigned short(16 bits).
     * 读取一个无符号双字节.
     */
    public short ReadUint16() {
        short value = 0;
        value |= (this.BUF[this._position] & 0xFF);
        value |= ((this.BUF[this._position + 1] & 0xFF) << 8);
        this.MovPosition(2);
        return value;
    }

    /**
     * Read a int(32 bits).
     * 读取一个四字节.
     */
    public int ReadInt32() {
        int value = 0;
        value |= (this.BUF[this._position] & 0xFF);
        value |= ((this.BUF[this._position + 1] & 0xFF) << 8);
        value |= ((this.BUF[this._position + 2] & 0xFF) << 16);
        value |= ((this.BUF[this._position + 3] & 0xFF) << 24);
        this.MovPosition(4);
        return value;
    }

    /**
     * Read a unsigned int(32 bits).
     * 读取一个无符号四字节.
     */
    public int ReadUint32() {
        int value = 0;
        value |= (this.BUF[this._position] & 0xFF);
        value |= ((this.BUF[this._position + 1] & 0xFF) << 8);
        value |= ((this.BUF[this._position + 2] & 0xFF) << 16);
        value |= ((this.BUF[this._position + 3] & 0xFF) << 24);
        this.MovPosition(4);
        return value;
    }

    /**
     * Read a float(32 bits).
     * 读取一个四字节浮点数.
     */
    public Float ReadFloat32() {
        int value = 0;
        value |= (this.BUF[this._position] & 0xFF);
        value |= ((this.BUF[this._position + 1] & 0xFF) << 8);
        value |= ((this.BUF[this._position + 2] & 0xFF) << 16);
        value |= ((this.BUF[this._position + 3] & 0xFF) << 24);
        this.MovPosition(4);
        return Float.intBitsToFloat(value);
    }

    /**
     * Read a double(64 bits).
     * 读取一个八字节浮点数.
     */
    public Double ReadFloat64() {
        long value = 0;
        value |= (this.BUF[this._position] & 0xFFL);
        value |= ((this.BUF[this._position + 1] & 0xFFL) << 8);
        value |= ((this.BUF[this._position + 2] & 0xFFL) << 16);
        value |= ((this.BUF[this._position + 3] & 0xFFL) << 24);
        value |= ((this.BUF[this._position + 4] & 0xFFL) << 32);
        value |= ((this.BUF[this._position + 5] & 0xFFL) << 40);
        value |= ((this.BUF[this._position + 6] & 0xFFL) << 48);
        value |= ((this.BUF[this._position + 7] & 0xFFL) << 56);
        this.MovPosition(8);
        return Double.longBitsToDouble(value);
    }

    /**
     * Read a binary.
     * 读取一个二进制对象.
     */
    public ByteCool ReadBin(int l) {
        int max = this.GetBytesReadable();
        if (l > max) {
            l = max;
        }

        ByteCool dest = new ByteCool(l);
        this.copyBytes(this.BUF, this._position, dest.BUF, 0, l);
        dest._length = l;

        this.MovPosition(l);
        return dest;
    }

    /**
     * Read a array of bytes.
     * 读取多个字节.
     */
    public byte[] ReadBytes(int l) {
        int max = this.GetBytesReadable();
        if (l > max) {
            l = max;
        }

        byte[] dest = new byte[l];
        this.copyBytes(this.BUF, this._position, dest, 0, l);

        this.MovPosition(l);
        return dest;
    }

    /**
     * Read a utf8 string.
     * 读取一个UTF8字符串.
     */
    public String ReadUTF8(int l) {
        int max = this.GetBytesReadable();
        if (l > max) {
            l = max;
        }

        byte[] dest = new byte[l];
        this.copyBytes(this.BUF, this._position, dest, 0, l);
        String str = null;
        try {
            str = new String(dest, "UTF-8");
        } catch (Exception e) {
            System.out.printf("[ERR] ReadUTF8:%v\n", e);
        }

        this.MovPosition(l);
        return str;
    }

    /**
     * Read a array of bytes(within length in byte array).
     * 读取一个UTF8字符串(携带长度).
     */
    public String ReadLenUTF8() {
        int l = (int) this.ReadUint8();
        if (l == 0xFE) {
            l = (int) this.ReadUint16();
        } else if (l == 0xFF) {
            l = this.ReadInt32();
        }
        return this.ReadUTF8(l);
    }

    /**
     * Read a utf8 string(within length in byte array).
     * 读取多个字节(携带长度).
     */
    public byte[] ReadLenBytes() {
        int l = (int) this.ReadUint8();
        if (l == 0xFE) {
            l = (int) this.ReadUint16();
        } else if (l == 0xFF) {
            l = this.ReadInt32();
        }
        return this.ReadBytes(l);
    }

    /**
     * Read a binary(within length in byte array).
     * 读取一个二进制对象(携带长度).
     */
    public ByteCool ReadLenBin() {
        int l = (int) this.ReadUint8();
        if (l == 0xFE) {
            l = (int) this.ReadUint16();
        } else if (l == 0xFF) {
            l = this.ReadInt32();
        }
        return this.ReadBin(l);
    }
//================================================
//
//  write
//	写入
//
//================================================

    /**
     * Write a byte(8 bits).
     * 写入一个字节.
     */
    public void WriteInt8(byte value) {
        int l = 1;
        this.occupy(l);
        this.BUF[this._length] = value;
        this.MovLength(l);
    }

    /**
     * Write a unsigned byte(8 bits).
     * 写入一个无符号字节.
     */
    public void WriteUint8(byte value) {
        int l = 1;
        this.occupy(l);
        this.BUF[this._length] = value;
        this.MovLength(l);
    }

    /**
     * Write a short(16 bits).
     * 写入一个双字节.
     */
    public void WriteInt16(short value) {
        int l = 2;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFF));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00) >>> 8);
        this.MovLength(l);
    }

    /**
     * Write a unsigned short(16 bits).
     * 写入一个无符号双字节.
     */
    public void WriteUint16(short value) {
        int l = 2;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFF));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00) >>> 8);
        this.MovLength(l);
    }

    /**
     * Write a int(32 bits).
     * 写入一个无符号四字节.
     */
    public void WriteInt32(int value) {
        int l = 4;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFF));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00) >>> 8);
        this.BUF[this._length + 2] = (byte) ((value & 0xFF0000) >>> 16);
        this.BUF[this._length + 3] = (byte) ((value & 0xFF000000) >>> 24);
        this.MovLength(l);
    }

    /**
     * Write a unsigned int(32 bits).
     * 写入一个无符号四字节.
     */
    public void WriteUint32(int value) {
        int l = 4;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFF));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00) >>> 8);
        this.BUF[this._length + 2] = (byte) ((value & 0xFF0000) >>> 16);
        this.BUF[this._length + 3] = (byte) ((value & 0xFF000000) >>> 24);
        this.MovLength(l);
    }

    /**
     * Write a float(32 bits).
     * 写入一个四字节浮点数.
     */
    public void WriteFloat32(float number) {
        int value = Float.floatToIntBits(number);
        int l = 4;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFF));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00) >>> 8);
        this.BUF[this._length + 2] = (byte) ((value & 0xFF0000) >>> 16);
        this.BUF[this._length + 3] = (byte) ((value & 0xFF000000) >>> 24);
        this.MovLength(l);
    }

    /**
     * Write a double(64 bits).
     * 写入一个八字节浮点数.
     */
    public void WriteFloat64(double number) {
        long value = Double.doubleToLongBits(number);
        int l = 8;
        this.occupy(l);
        this.BUF[this._length] = (byte) ((value & 0xFFL));
        this.BUF[this._length + 1] = (byte) ((value & 0xFF00L) >>> 8);
        this.BUF[this._length + 2] = (byte) ((value & 0xFF0000L) >>> 16);
        this.BUF[this._length + 3] = (byte) ((value & 0xFF000000L) >>> 24);
        this.BUF[this._length + 4] = (byte) ((value & 0xFF00000000L) >>> 32);
        this.BUF[this._length + 5] = (byte) ((value & 0xFF0000000000L) >>> 40);
        this.BUF[this._length + 6] = (byte) ((value & 0xFF000000000000L) >>> 48);
        this.BUF[this._length + 7] = (byte) ((value & 0xFF00000000000000L) >>> 56);
        this.MovLength(l);
    }

    /**
     * Write a binary.
     * 写入一个二进制对象.
     */
    public void WriteBin(ByteCool value) {
        int l = value._length;
        if (l == 0) {
            return;
        }
        this.occupy(l);
        this.copyBytes(value.BUF, 0, this.BUF, this._length, l);
        this.MovLength(l);
    }

    /**
     * Write a utf8 string.
     * 写入一个UTF8字节串.
     */
    public void WriteUTF8(String value) {
        int l = value.length();
        if (l == 0) {
            return;
        }
        this.occupy(l);
        this.copyBytes(value.getBytes(), 0, this.BUF, this._length, l);
        this.MovLength(l);
    }

    /**
     * Write a array of bytes.
     * 写入多个字节.
     */
    public void WriteBytes(byte[] value) {
        int l = value.length;
        if (l == 0) {
            return;
        }
        this.occupy(l);
        this.copyBytes(value, 0, this.BUF, this._length, l);
        this.MovLength(l);
    }

    /**
     * Write a utf8 string(within length in byte array).
     * 写入一个UTF8字符串(携带长度).
     */
    public void WriteLenUTF8(String value) {
        int l = value.length();
        if (l > 0xFFFF) {
            this.WriteUint8((byte) (0xFF));
            this.WriteUint32(l);
        } else if (l >= 0xFF) {
            this.WriteUint8((byte) (0xFE));
            this.WriteUint16((short) l);
        } else {
            this.WriteUint8((byte) l);
        }
        this.WriteUTF8(value);
    }

    /**
     * Write a array of bytes(within length in byte array).
     * 写入多个字节(携带长度).
     */
    public void WriteLenBytes(byte[] value) {
        int l = value.length;
        if (l > 0xFFFF) {
            this.WriteUint8((byte) (0xFF));
            this.WriteUint32(l);
        } else if (l >= 0xFF) {
            this.WriteUint8((byte) (0xFE));
            this.WriteUint16((short) l);
        } else {
            this.WriteUint8((byte) l);
        }
        this.WriteBytes(value);
    }

    /**
     * Write a binary(within length in byte stream).
     * 写入一个二进制对象(携带长度).
     */
    public void WriteLenBin(ByteCool value) {
        int l = value.GetLength();
        if (l > 0xFFFF) {
            this.WriteUint8((byte) (0xFF));
            this.WriteUint32(l);
        } else if (l >= 0xFF) {
            this.WriteUint8((byte) (0xFE));
            this.WriteUint16((short) l);
        } else {
            this.WriteUint8((byte) l);
        }
        this.WriteBin(value);
    }

//================================================
//
//  special
//	特殊
//
//================================================

    /**
     * Copy bytes.
     * 拷贝字节.
     */
    private void copyBytes(byte[] src, int srcPos, byte[] dst, int dstPos, int srcLen) {
        System.arraycopy(src, srcPos, dst, dstPos, srcLen);
    }

    /**
     * Occupy bytes.
     * 占据字节数.
     */
    private void occupy(int l) {
        int need = this._length + l; // 当length == size时, 再写入一个0字节会引发出错
        if (need <= this._size) {
            return;
        }
        int i = 0;
        int temp = need;
        for (; ; ) {
            temp = temp / 2;
            i++;
            if (temp == 0) {
                break;
            }
        }
        this.SetSize(1 << i);
    }

    /**
     * Clone.
     * 克隆.
     */
    public ByteCool Clone(boolean shallow) {
        ByteCool dest = null;
        if (shallow == true) {
            dest = new ByteCool();
            dest._length = this._length;
            dest._position = 0;
            dest._size = this._size;
            dest.BUF = this.BUF;
        } else {
            dest = new ByteCool(this._length);
            this.copyBytes(this.BUF, 0, dest.BUF, 0, this._length);
            dest._length = this._length;
        }
        return dest;
    }
}